/* ******************************************************************************
* 2019 - present Contributed by Apulis Technology (Shenzhen) Co. LTD
*
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available at
* https://www.opensource.org/licenses/MIT
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: MIT
***************************************************************************** */
package jobscheduler

import (
	"encoding/json"
	"fmt"
)

// create distributed job
// JobBase.resType == RESOURCE_TYPE_DISTRIBUTED_JOB
// POST api/v1/distributed-jobs
type CreateDistributedJobReq struct {
	DistributedJob
}

// delete distributed application
// DELETE api/v1/distributed-jobs/:id

type DistributedJob struct {

	// common data
	JobBase	JobBase `json:"jobBase"`

	// job meta
	MetaData MetaData `json:"metaData"`

	// job list
	VcJob
}

func NewDistributedJob() *DistributedJob {
	return &DistributedJob{
		JobBase: JobBase{},
		VcJob: VcJob{
			Tasks:   make([]VcJobTask, 0),
		},
	}
}

func (d *DistributedJob) SetResType(resType ResourceType)  {
	d.JobBase.ResType = resType
}

func (d *DistributedJob) SetJobId(jobId string)  {
	d.JobBase.JobId = jobId
}

func (d *DistributedJob) ToString() string {
	data, _ := json.Marshal(*d)
	return string(data)
}

func (d *DistributedJob) FromString(data string) error {
	return json.Unmarshal([]byte(data), d)
}


type VcJob struct {

	// master pods, worker pods
	Tasks []VcJobTask `json:"tasks"`
}

type VcJobTask struct {

	TaskName string `json:"taskName"`
	Replicas int `json:"replicas"`
	Container *Container `json:"container"`
	InitContainer *Container `json:"initContainer"`
	ArchType string `json:"archType"`
}

func (t *VcJobTask) GetTaskName() string {
	return t.TaskName
}

func (t *VcJobTask) GetContainer() *Container {
	return t.Container
}

func (t *VcJobTask) GetInitContainer() *Container {
	return t.InitContainer
}

func (t *VcJobTask) GetNodeSelector() map[string]string {

	selector := make(map[string]string)
	selector["archType"] = t.ArchType

	return selector
}

func (t *VcJobTask) GetReplicas() int {
	return t.Replicas
}

func (t *VcJobTask) GetTaskSpecificLabels() map[string]string {
	return map[string]string{
		"task-name" : t.GetTaskName(),
	}
}

func (t *VcJobTask) GetTaskAffinityLabels(jobId string) map[string]string {
	return map[string]string{
		"task-affinity" : fmt.Sprintf("%s-%s", jobId, t.GetTaskName()),
	}
}

func (t *VcJobTask) GetDeviceName() string {

	if t.GetContainer() != nil {

		quota := t.GetContainer().GetResourceQuota()
		if len(quota.Request.Device.DeviceType) > 0 && len(quota.Request.Device.DeviceNum) > 0 {
			return quota.Request.Device.DeviceType
		}

		if len(quota.Limit.Device.DeviceType) > 0 && len(quota.Limit.Device.DeviceNum) > 0 {
			return quota.Limit.Device.DeviceType
		}
	}

	return ""
}

func NewVcBatchJob() *VcJob {

	return &VcJob{
		Tasks:        make([]VcJobTask, 0),
	}
}

func (d *DistributedJob) GetReplicas() int {

	count := 0
	for _, task := range d.VcJob.Tasks {
		count += task.Replicas
	}

	return count
}

func (d *DistributedJob) GetUserName() string {

	return d.JobBase.Owner
}

func (d *DistributedJob) GetNamespace() string {

	return d.JobBase.GetNamespace()
}

func (d *DistributedJob) GetJobId() string {
	return d.JobBase.JobId
}

func (d *DistributedJob) GetModId() int {
	return d.JobBase.ModId
}

func (d *DistributedJob) GetResType() ResourceType {
	return d.JobBase.ResType
}

func (d *DistributedJob) GetLabels() map[string]string {

	// labels empty
	labels := make(map[string]string)

	// job-id
	labels["job-id"] = d.GetJobId()
	return labels
}

func (d *DistributedJob) GetContainerPorts() map[string][]ContainerPort {

	// ports
	portsMap := make(map[string][]ContainerPort)
	for _, task := range d.Tasks {
		if ports := task.Container.GetPorts(); len(ports) > 0 {
			portsMap[task.GetTaskName()] = ports
		}
	}

	return portsMap
}

func (d *DistributedJob) GetComputeDeviceName() string {

	if len(d.VcJob.Tasks) >  0 {
		return d.VcJob.Tasks[0].GetDeviceName()
	}

	return ""
}

func (d *DistributedJob) DisableIstio()  {

	annotation := d.MetaData.GetAnnotations()
	if annotation == nil {
		annotation = make(map[string]string)
	}

	annotation["sidecar.istio.io/inject"] = "false"
	d.MetaData.SetAnnotations(annotation)

	return
}

func (d *DistributedJob) GetAnnotations() map[string]string  {

	return d.MetaData.GetAnnotations()
}



//
//func (s *SparkPodSpec) SetLabels(labels map[string]string) {
//	s.Labels = labels
//}

//func (v *VcJob) Validate() error {
//
//	if v.JobBase.ModId == 0 {
//		return fmt.Errorf("invalid module id: %d", v.JobBase.ModId)
//	}
//
//	resType := v.JobBase.ResType
//	if resType < RESOURCE_TYPE_POD || resType >= RESOURCE_TYPE_UNKONWN {
//		return fmt.Errorf("invalid module id: %d", v.JobBase.ResType)
//	}
//
//	return nil
//}

//
//func (s *VcJob) GetSparkVersion() string {
//	return s.SparkVersion
//}

//
//func (s *SparkJob) GetDeployMode() string {
//	return "cluster"
//}
//
//func (s *SparkJob) GetImage() string {
//	return s.Image
//}
//
//func (s *SparkJob) GetMainAppFile() string {
//	return s.MainAppFile
//}
//
//func (s *SparkJob) GetMainClass() string {
//	return s.MainClass
//}
//
//func (s *SparkJob) GetArguments() []string {
//	return s.Arguments
//}
//
//func (s *SparkJob) GetMounts() []MountPoint {
//	return s.MountPoints
//}

//func (v *VcJob) ToString() string {
//	data, _ := json.Marshal(*v)
//	return string(data)
//}
//
//func (v *VcJob) FromString(data string) error {
//	return json.Unmarshal([]byte(data), v)
//}


